export default class Layer {
  constructor(option) {
    this.Vm = option.Vm;
    this.viewer = option.viewer;
    this.layerList = [];
  }

  loadLayer (option) {
    const { resourceId, serverType, serverUrl, apiType, show, position, isFirst } = option;
    let curLayer = this.layerList.find(el => el.attribute.resourceId == resourceId);
    if (curLayer) {
      this.removeLayer(resourceId);
      curLayer = null;
    };

    switch (serverType) {
      case 'WMTS':
        curLayer = this.loadWMTS(option);
        break;

      case 'WMS':
        curLayer = this.loadWMS(option);
        break;

      case 'XYZ':
        if (apiType == 'rasterserver') {
          curLayer = this.loadXYZVec(option);
        } else if (apiType == 'mapserver') {
          switch (true) {
            case serverUrl.includes('getMap'):
              curLayer = this.loadXYZVec(option);
              break;

            case serverUrl.includes('getDatas'):
              curLayer = this.loadXYZLabel(option);
              break;

            default:
              break;
          }
        }
        break;

      default:
        break;
    }
    if (!curLayer) return;
    curLayer.attribute = option;
    curLayer.show = show;
    this.viewer.imageryLayers.add(curLayer);
    this.layerList.push(curLayer);
    if (isFirst) this.setView(position);

    setTimeout(() => {
      typeof callback == 'function' && callback();
    }, 100);
  }

  loadWMTS (option) {
    const { serverUrl, serverStyleUrl } = option;
    let curLayer = new Cesium.ImageryLayer(
      new Cesium.WebMapTileServiceImageryProvider({
        url: serverStyleUrl || serverUrl,
        layer: '',
        style: 'default',
        format: 'image/jpeg',
        tileMatrixSetID: 'default028mm',
        tilingScheme: new Cesium.GeographicTilingScheme(),
        tileMatrixLabels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19'],
        maximumLevel: 20,
        tileWidth: 256,
        tileHeight: 256
      })
    );
    return curLayer;
  }

  loadWMS (option) {
    const { serverUrl, serverStyleUrl } = option;
    let curLayer = new Cesium.ImageryLayer(
      new Cesium.WebMapServiceImageryProvider({
        url: serverStyleUrl || serverUrl,
        layers: '',
        parameters: {
          service: 'WMS',
          format: 'image/png',
          transparent: true
        }
      })
    );
    return curLayer;
  }

  loadXYZVec (option) {
    const { serverUrl, tilesize, serverStyleUrl } = option;
    const tileMatrixLabels = tilesize == 512 ? ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20'] : ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20'];
    let curLayer = new Cesium.ImageryLayer(
      new Cesium.WebMapTileServiceImageryProvider({
        url: serverStyleUrl || serverUrl,
        layer: "",
        style: "",
        format: "",
        tileMatrixSetID: "",
        tileWidth: tilesize,
        tileHeight: tilesize,
        tilingScheme: new Cesium.GeographicTilingScheme(),
        tileMatrixLabels: tileMatrixLabels,
        maximumLevel: 20,
      })
    );
    return curLayer;
  }

  loadXYZLabel (option) {
    const { serverUrl, tilesize } = option;
    const tileMatrixLabels = tilesize == 512 ? ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20'] : ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20'];
    let curLayer = new Cesium.ImageryLayer(
      new Custom.LabelTileServiceImageryProvider(this.viewer, {
        url: serverUrl,
        tilingScheme: new Cesium.GeographicTilingScheme({
          numberOfLevelZeroTilesX: 2,
          numberOfLevelZeroTilesY: 1,
        }),
        tileMatrixLabels: tileMatrixLabels,
        offsetHeight: 55,
        maximumLevel: 22,
        tileWidth: tilesize,
        tileHeight: tilesize,
        dataType: "binary",
        needDecode: false,
        fontName: "微软雅黑",
        glyphUrl: "data/font/{fontstack}/{range}.pbf",
        defaultHeight: 63
      })
    );
    return curLayer;
  }

  loadWhiteFilm (option) {
    const { resourceId, serverName, styleName, layerData, heightField, magnification, color, opacity, callback, serverIpPort } = option;
    let curLayer = this.layerList.find(el => el.attribute.resourceId == resourceId);
    if (curLayer) {
      let houseTileServiceImageryProvider = new Cesium.ImageryLayer(
        new Cesium.HouseTileServiceImageryProvider(this.viewer, {
          url: `${serverIpPort}/mapserver/data/${serverName}/getData?x={x}&y={y}&l={z}&styleId=${styleName}&tilesize=256`,
          tilingScheme: new Cesium.GeographicTilingScheme({ numberOfLevelZeroTilesX: 2, numberOfLevelZeroTilesY: 1 }),
          tileMatrixLabels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22"],
          maximumLevel: 20,
          tileWidth: 256,
          tileHeight: 256,
          needDecode: false, // 是否需要数据解码
          translucent: opacity < 1 ? true : false,
          opacity: opacity,
          dataType: 'binary',
          fillColor: color, // 房屋颜色
          // opacity: 0.5, // 房屋透明度
          filterLayerId: [layerData], // 房屋图层
          heightProperty: heightField, // 房屋高度字段
          heightScale: `${magnification}`,
          showLevel: 13,
        })
      );
      option.type = 'whiteFilm';
      option.resourceId = `${resourceId}_whiteFilm`;
      houseTileServiceImageryProvider.attribute = option;
      this.viewer.imageryLayers.add(houseTileServiceImageryProvider);
      this.layerList.push(houseTileServiceImageryProvider);

      setTimeout(() => {
        typeof callback == 'function' && callback();
      }, 100);
    }
  }

  // 图层显隐
  hideLayer (resourceId, state) {
    let curLayer = this.layerList.find(el => el.attribute.resourceId == resourceId);
    if (curLayer && curLayer.attribute.isExist) {
      curLayer.show = state;
      curLayer.attribute.show = state;
    }
  }

  // 删除图层
  removeLayer (resourceId = '') {
    if (this.layerList.length) {
      if (resourceId) {
        for (let i = 0; i < this.layerList.length; i++) {
          const item = this.layerList[i];
          if (item.attribute.resourceId == resourceId) {
            this.viewer.imageryLayers.remove(item);
            this.layerList.splice(i, 1);
            i--;
          }
        }
      } else {
        for (let i = 0; i < this.layerList.length; i++) {
          const item = this.layerList[i];
          this.viewer.imageryLayers.remove(item);
        }
        this.layerList = [];
      }
    }
  }

  setView (position, callback) {
    const { lng, lat, height, heading, pitch, roll } = position;
    if (!lng || !lat || !height) return;
    this.viewer.camera.setView({
      destination: Cesium.Cartesian3.fromDegrees(lng, lat, height + 200),
      orientation: { heading: Cesium.Math.toRadians(heading || 0), pitch: Cesium.Math.toRadians(pitch || -90), roll: Cesium.Math.toRadians(roll || 0) },
      complete: callback && callback()
    });
  }

  getServerUrlInfo (serverType, serverUrl) {
    const regImage = /rasterserver.*?/;
    const regVec = /mapserver.*?/;
    const regTilesize = new RegExp('(?<=tilesize=)[^&]*');
    let serverIpPort = '';
    let apiType = '';
    let dataType = '';
    let isStandard = false;
    let tilesize = 512;
    switch (true) {
      // 影像地址
      case regImage.test(serverUrl):
        apiType = 'rasterserver';
        switch (serverType) {
          case 'WMTS':
            const regImageWMTS = /http:\/\/([\w.]+\/?)\S*\/rasterserver\/image\/WMTS\/1.0\/([\s\S]*)\/(G|g)etTile\/{TileMatrix}\/{TileRow}\/{TileCol}/;
            if (regImageWMTS.test(serverUrl)) {
              isStandard = true;
            }
            break;

          case 'XYZ':
            const regImageXYZ = /http:\/\/([\w.]+\/?)\S*\/rasterserver\/image\/([\s\S]*)\/{TileMatrix}\/{TileCol}\/{TileRow}\/(G|g)etMap/;
            if (regImageXYZ.test(serverUrl)) {
              isStandard = true;
              const tilesizeStr = serverUrl.match(regTilesize);
              if (tilesizeStr) tilesize = Number(tilesizeStr[0]);
            }
            break;

          default:
            apiType = '';
            isStandard = false;
            break;
        }
        break;

      // 矢量地址
      case regVec.test(serverUrl):
        apiType = 'mapserver';
        switch (serverType) {
          case 'WMTS':
            const regVecWMTS = /http:\/\/([\w.]+\/?)\S*\/mapserver\/(layer|label)\/WMTS\/1.0\/([\s\S]*)\/([\s\S]*)\/(G|g)etTile\/{TileMatrix}\/{TileRow}\/{TileCol}/;
            if (regVecWMTS.test(serverUrl)) {
              isStandard = true;
              dataType = serverUrl.includes('layer') ? 'layer' : 'label';
            }
            break;

          case 'WMS':
            const regVecWMS = /http:\/\/([\w.]+\/?)\S*\/mapserver\/(layer|label)\/WMS\/(1.1.1|1.3.0|1.1.0)\/([\s\S]*)\/([\s\S]*)\/(G|g)etMap/;
            if (regVecWMS.test(serverUrl)) {
              isStandard = true;
              dataType = serverUrl.includes('layer') ? 'layer' : 'label';
            }
            break;

          case 'XYZ':
            const regVecXYZ = /http:\/\/([\w.]+\/?)\S*\/mapserver\/(layer|vmap|label)([\s\S]*)\/((G|g)etMap|(G|g)etDatas)\?styleId=([\s\S]*)/;
            if (regVecXYZ.test(serverUrl)) {
              isStandard = true;
              dataType = serverUrl.includes('layer') || serverUrl.includes('vmap') ? 'layer' : 'label';
              const tilesizeStr = serverUrl.match(regTilesize);
              if (tilesizeStr) tilesize = Number(tilesizeStr[0]);
            }
            break;

          default:
            apiType = '';
            isStandard = false;
            break;
        }
        break;

      default:
        apiType = '';
        isStandard = false;
        break;
    }
    if (isStandard) {
      const regIpPort = new RegExp('(http|https)://(.*?):(.*?)/(.*)');
      const matchArr = serverUrl.match(regIpPort);
      matchArr && (serverIpPort = `${matchArr[1]}://${matchArr[2]}:${matchArr[3]}`);
    }
    const testUrl = this.getTestUrl({ serverType, apiType, dataType, serverUrl });
    return { isStandard, serverIpPort, apiType, dataType, tilesize, testUrl };
  }

  getTestUrl (layerInfo) {
    const { serverType, apiType, dataType, serverUrl } = layerInfo;
    let testUrl = '';
    switch (apiType) {
      case 'rasterserver':
        switch (serverType) {
          case 'WMTS':
            testUrl = serverUrl.replace('{TileMatrix}/{TileRow}/{TileCol}', '16/9881/53577');
            break;

          case 'XYZ':
            testUrl = serverUrl.replace('{TileMatrix}/{TileCol}/{TileRow}', '16/26785/4954');
            break;

          default:
            break;
        }
        break;

      case 'mapserver':
        switch (serverType) {
          case 'WMTS':
            testUrl = serverUrl.replace('{TileMatrix}/{TileRow}/{TileCol}', '16/9881/53577');
            break;

          case 'WMS':
            testUrl = `${serverUrl}?service=WMS&format=image/png&transparent=true&version=1.1.1&request=GetMap&styles=&layers=&bbox=114.2962646484375,35.72479248046875,114.29901123046874,35.7275390625&width=256&height=256&srs=EPSG:4326`;
            break;

          case 'XYZ':
            switch (true) {
              case serverUrl.includes('getMap'):
                testUrl = serverUrl.replace('x={TileCol}&y={TileRow}&l={TileMatrix}', 'x=16&y=9881&l=53577');
                break;

              case serverUrl.includes('getDatas'):
                testUrl = serverUrl.replace('x={x}&y={y}&l={z}', 'x=16&y=9881&l=53577');
                break;

              default:
                break;
            }
            break;

          default:
            break;
        }
        break;

      default:
        break;
    }
    return testUrl;
  }

  loadLayerFile (data) {
    for (let i = 0; i < data.length; i++) {
      const item = data[i];
      const attribute = item.attribute || null;
      const isExist = attribute.isExist || null;
      if (!attribute || !isExist) break;
      this.loadLayer(attribute);
      const whiteFilmStretching = attribute.whiteFilmStretching || null;
      if (whiteFilmStretching) this.loadWhiteFilm(whiteFilmStretching);
    }
  }

  destroy () {
    this.removeLayer();
  }
}